[go

您所在的位置:网站首页 golang 验证器 [go

[go

2024-07-15 04:36| 来源: 网络整理| 查看: 265

目录1.validator简介2.常用示例3.进阶示例-自定义字段或验证方法3.1 自定义规则3.2 自定义规则在gin中使用4.binding && validator5.示例-用户名与密码校验

1.validator简介

validator是一个开源的验证器包,可以快速校验输入信息是否符合自定规则。源码地址: https://github.com/go-playground/validator

本地开发安装库:

go get github.com/go-playground/validator 2.常用示例

例如我们使用golang的gin框架进行web server的开发,对于传来的json参数进行校验,这个是必不可少的,只要是传过来的参数,就不可信。

validate的tag校验类型见官方文档-参考。

话不多说,直接上代码示例:

package main import ( "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" "net/http" ) type User struct { Username string `json:"username" validate:"required,min=4,max=20"` // 必填字段,限制长度 Password string `json:"password" validate:"required"` // 必填字段 Email string `json:"email" validate:"required,email"` // 限于email格式 Phone string `json:"phone" validate:"omitempty,numeric"` // 限于数字型 Hobby []string `json:"hobby" validate:"omitempty"` // 空时忽略 Age int `json:"age" validate:"omitempty,gt=18,lt=100"` // 限制大小 Gender string `json:"gender" validate:"omitempty,oneof=male female"` // 限于男女 } func main() { router := gin.Default() router.POST("/login", login) _ = router.Run(":8080") } func login(ctx *gin.Context) { var user User err := ctx.ShouldBindJSON(&user) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) return } // repeat parse use below //_ = ctx.ShouldBindWith(&user, binding.JSON) validate := validator.New() err = validate.Struct(user) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) return } ctx.JSON(http.StatusOK, gin.H{"msg": "success"}) }

启动server,postman测试,可以看到哪些字段因为某个校验不能通过校验,导致error, 是不是很友好呢,不过建议返回前台校验参数失败即可,具体校验详情作为日志输出到server的log文件中。

3.进阶示例-自定义字段或验证方法 3.1 自定义规则

代码源自: http://liuqh.icu/2021/05/30/go/gin/11-validate/

package main import ( "fmt" "github.com/go-playground/validator/v10" ) // 验证pre type CustomParam struct { Pre string `validate:"pre=go_"` } func main() { // 实例化验证器 validate = validator.New() // 注册自定义标签 _ = validate.RegisterValidation("pre", ValidatePre) cusParam := CustomParam{ Pre: "php_", } err := validate.Struct(cusParam) fmt.Println(err) } // 自定义验证规则 func ValidatePre(fl validator.FieldLevel) bool { return fl.Field().String() == "go_" } 3.2 自定义规则在gin中使用

代码源自: http://liuqh.icu/2021/05/30/go/gin/11-validate/ 有自定义的validator,tag的类型设为binding。

package main import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" "net/http" "time" ) // 定义结构体 type User struct { Name string `form:"name" binding:"required,min=3,max=5" ` BirthDate time.Time `form:"date" binding:"required,birth" time_format:"2006-01-02"` } // 运行程序 func main() { engine := gin.Default() // 注册自定义验证标签:birth if validate,ok := binding.Validator.Engine().(*validator.Validate);ok { validate.RegisterValidation("birth",checkBirthDate) } // 接收请求 engine.GET("/valid", func(context *gin.Context) { var user User // 集成验证 err := context.ShouldBindQuery(&user) if err != nil { context.JSON(http.StatusBadRequest,gin.H{"error":err.Error()}) return } context.JSON(http.StatusOK,gin.H{"msg":"success"}) }) _ = engine.Run() } // 检测生日 func checkBirthDate(fl validator.FieldLevel) bool { t,ok := fl.Field().Interface().(time.Time) if ok { // 当前时间应该大于生日时间 if time.Now().After(t) { return true } } return false } 4.binding && validator

见参考文档:Gin请求参数校验

5.示例-用户名与密码校验 package main import ( "fmt" "github.com/go-playground/validator/v10" "reflect" "regexp" ) func main() { u := User{ Username: "IamJames", Password: "1234567A$888", } validate := validator.New() _ = validate.RegisterValidation("minLen", minLen) _ = validate.RegisterValidation("verifyPwd", verifyPwd) err := validate.Struct(u) if err != nil { errInfo := processErr(u, err) fmt.Printf("error: %v\n", err) fmt.Printf("errorInfo: %v\n", errInfo) return } fmt.Println("validate pass...") } type User struct { Username string `json:"username,omitempty" validate:"required,minLen" field_error_info:"用户名最少6个字符"` Password string `json:"password,omitempty" validate:"required,verifyPwd" field_error_info:"密码应包含数字、大/小写字母、特殊字符中的3种, 且至少8个字符"` } func minLen(f validator.FieldLevel) bool { val := f.Field().String() if len(val) < 6 { return false } return true } func verifyPwd(f validator.FieldLevel) bool { val := f.Field().String() if len(val) < 8 || len(val) > 20 { // length需要通过验证 fmt.Println("pwd length error") return false } pwdPattern := `^[0-9a-zA-Z!@#$%^&*~-_+]{8,20}$` reg, err := regexp.Compile(pwdPattern) // filter exclude chars if err != nil { return false } match := reg.MatchString(val) if !match { fmt.Println("not match error.") return false } var cnt int = 0 // 满足3中以上即可通过验证 patternList := []string{ // 数字、大小写字母、特殊字符 `[0-9]+`, `[a-z]+`, `[A-Z]+`, `[!@#$%^&*~-_+]+`, } for _, pattern := range patternList { match, _ = regexp.MatchString(pattern, val) if match { cnt++ } } if cnt < 3 { fmt.Println("pwd should include at least 3 types.") return false } return true } func processErr(u interface{},err error) string { if err == nil { //如果为nil 说明校验通过 return "" } invalid, ok := err.(*validator.InvalidValidationError) //如果是输入参数无效,则直接返回输入参数错误 if ok { return "输入参数错误:" + invalid.Error() } validationErrs := err.(validator.ValidationErrors) //断言是ValidationErrors for _, validationErr := range validationErrs { fieldName := validationErr.Field() //获取是哪个字段不符合格式 field, ok := reflect.TypeOf(u).FieldByName(fieldName) //通过反射获取filed if ok { errorInfo := field.Tag.Get("field_error_info") //获取field对应的reg_error_info tag值 return fieldName + ": " + errorInfo //返回错误 }else { return "缺失field_error_info" } } return "" }

参考文档

1.Gin框架(十一):验证器Validator使用 2.github-官方库 3.GIn 自定义validator 使用binding还是validate的问题 4.golang学习之gin(五):数据绑定及验证 5.golang: 密码中允许出现数字、大写字母、小写字母、特殊字符,但至少包含其中2种且长度在8-16之间(四种符号任意满足三种即可)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3